﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;

namespace ChessKit.Common
{
  public static class VisualTreeExtensions
  {
    public static T HitTest<T>(this Visual visual, Point position)
      where T : class
    {
      if (visual == null) return null;
      T res = null;
      VisualTreeHelper.HitTest(
        visual,
        dp =>
          {
            res = dp as T;
            return res != null
                     ? HitTestFilterBehavior.Stop
                     : HitTestFilterBehavior.Continue;

          },
        hal =>
          {
            res = hal.VisualHit as T;
            return res != null
                     ? HitTestResultBehavior.Stop
                     : HitTestResultBehavior.Continue;
          },
        new PointHitTestParameters(position));
      return res;
    }

    public static T HitTest<T>(this Visual visual, Point position, Func<T, bool> predicate)
      where T : class
    {
      if (visual == null) return null;
      T res = null;
      VisualTreeHelper.HitTest(
        visual,
        dp =>
          {
            var x = dp as T;
            if (x != null && predicate(x))
            {
              res = x;
              return HitTestFilterBehavior.Stop;
            }
            else
              return HitTestFilterBehavior.ContinueSkipSelf;
          },
        hal =>
          {
//            res = hal.VisualHit as T;
//            if (res != null && predicate(res)) 
              return HitTestResultBehavior.Stop;
//            else 
//              return HitTestResultBehavior.Continue;
          },
        new PointHitTestParameters(position));
      return res;
    }

    public static IEnumerable<T> FindVisualChildren<T>(this DependencyObject element)
      where T : class
    {
      if (element == null) yield break;
      if (element is T)
        yield return (T)(object)element;

      var count = VisualTreeHelper.GetChildrenCount(element);
      for (int i = 0; i < count; i++)
      {
        var child = VisualTreeHelper.GetChild(element, i);
        foreach (var res in FindVisualChildren<T>(child))
          yield return res;
      }
    }

    public static T FindVisualParent<T>(this DependencyObject element)
      where T : class 
    {
      while (element != null)
      {
        if (element is T) return (T)(object)element;
        element = VisualTreeHelper.GetParent(element);
      }
      return null;
    }

    public static T FindVisualParent<T>(this DependencyObject element, Func<T, bool> predicate)
      where T : class 
    {
      while (element != null)
      {
        if (element is T)
        {
          var t = (T) (object) element;
          if (predicate(t)) return t;
        }

        element = VisualTreeHelper.GetParent(element);
      }
      return null;
    }

    public static DependencyObject GetTopLevelControl(this DependencyObject control)
    {
      var tmp = control;
      DependencyObject parent = null;
      while ((tmp = VisualTreeHelper.GetParent(tmp)) != null)
      {
        parent = tmp;
      }
      return parent;
    }
  }
}